from datetime import datetime, timedelta
from typing import Dict, Tuple, Any
from lunar_python import Solar

class BaziCalculator:
    """生辰八字计算器 - 使用 lunar_python 实现"""
    
    # 五行
    FIVE_ELEMENTS = {
        "甲": "木", "乙": "木", "丙": "火", "丁": "火", "戊": "土", "己": "土",
        "庚": "金", "辛": "金", "壬": "水", "癸": "水",
        "子": "水", "丑": "土", "寅": "木", "卯": "木", "辰": "土", "巳": "火",
        "午": "火", "未": "土", "申": "金", "酉": "金", "戌": "土", "亥": "水"
    }
    
    def __init__(self):
        pass
    
    def convert_to_solar_time(self, year: int, month: int, day: int, hour: int, minute: int, 
                              longitude: float = 116.4) -> Tuple[int, int, int, int, int]:
        """
        将北京时间转换为真太阳时
        
        Args:
            year: 年份
            month: 月份
            day: 日期
            hour: 小时（北京时间）
            minute: 分钟
            longitude: 经度（默认北京经度116.4度）
        
        Returns:
            (年, 月, 日, 时, 分) 真太阳时
        """
        # 北京时间是东经120度的地方时
        beijing_longitude = 120.0
        
        # 计算经度差导致的时差（每度4分钟）
        longitude_diff = longitude - beijing_longitude
        time_diff_minutes = longitude_diff * 4
        
        # 计算平太阳时
        beijing_time = datetime(year, month, day, hour, minute)
        mean_solar_time = beijing_time + timedelta(minutes=time_diff_minutes)
        
        # 计算真太阳时（考虑均时差）
        day_of_year = mean_solar_time.timetuple().tm_yday
        equation_of_time = self._calculate_equation_of_time(day_of_year)
        
        # 真太阳时 = 平太阳时 + 均时差
        true_solar_time = mean_solar_time + timedelta(minutes=equation_of_time)
        
        return (
            true_solar_time.year,
            true_solar_time.month,
            true_solar_time.day,
            true_solar_time.hour,
            true_solar_time.minute
        )
    
    def _calculate_equation_of_time(self, day_of_year: int) -> float:
        """
        计算均时差（分钟）
        """
        import math
        B = 360.0 / 365.0 * (day_of_year - 81)
        B_rad = math.radians(B)
        
        # 均时差公式（分钟）
        equation = 9.87 * math.sin(2 * B_rad) - 7.53 * math.cos(B_rad) - 1.5 * math.sin(B_rad)
        
        return equation
    
    def calculate_bazi(self, year: int, month: int, day: int, hour: int, minute: int = 0, 
                       use_solar_time: bool = True, longitude: float = 116.4) -> dict[str, int | Any]:
        """
        计算完整的生辰八字（使用 lunar_python）
        
        Args:
            year: 年份
            month: 月份
            day: 日期
            hour: 小时
            minute: 分钟
            use_solar_time: 是否使用真太阳时
            longitude: 经度（用于真太阳时计算）
        
        Returns:
            包含四柱八字的字典
        """
        # 如果使用真太阳时，先转换时间
        if use_solar_time:
            year, month, day, hour, minute = self.convert_to_solar_time(
                year, month, day, hour, minute, longitude
            )
        
        # 使用 lunar_python 计算八字
        # 创建公历日期对象
        solar = Solar.fromYmdHms(year, month, day, hour, minute, 0)
        
        # 转换为农历并获取八字
        lunar = solar.getLunar()
        eight_char = lunar.getEightChar()
        
        # 获取四柱
        year_pillar = eight_char.getYear()
        month_pillar = eight_char.getMonth()
        day_pillar = eight_char.getDay()
        hour_pillar = eight_char.getTime()
        
        return {
            "year_pillar": year_pillar,
            "month_pillar": month_pillar,
            "day_pillar": day_pillar,
            "hour_pillar": hour_pillar,
            "solar_year": year,
            "solar_month": month,
            "solar_day": day,
            "solar_hour": hour,
            "solar_minute": minute
        }
    
    def get_five_elements_analysis(self, bazi: Dict[str, str]) -> Dict[str, int]:
        """分析五行分布"""
        elements_count = {"木": 0, "火": 0, "土": 0, "金": 0, "水": 0}
        
        # 只处理八字柱（以 _pillar 结尾的键）
        pillar_keys = ["year_pillar", "month_pillar", "day_pillar", "hour_pillar"]
        
        for key in pillar_keys:
            if key in bazi:
                pillar = bazi[key]
                # 确保 pillar 是字符串
                if isinstance(pillar, str):
                    for char in pillar:
                        if char in self.FIVE_ELEMENTS:
                            element = self.FIVE_ELEMENTS[char]
                            elements_count[element] += 1
        
        return elements_count
    
    def get_zodiac_animal(self, year: int) -> str:
        """获取生肖"""
        solar = Solar.fromYmd(year, 1, 1)
        lunar = solar.getLunar()
        return lunar.getYearShengXiao()
